package _10_effective_java;

import java.math.BigInteger;
import java.time.Instant;
import java.util.EnumSet;
import java.util.Random;

/**
 * Effective Java 3rd Edition - Chapter 2
 *
 * 创建一个对象的技巧（表现形式）：
 *      1. 使用构造器，调用 new 方法
 *      2. 静态工厂方法
 *      3.
 */
public class _2_CreateObject {

    /** Item 1
     *  使用静态工厂方法相比 使用构造器方法的优点：
     *      1. 有名字，更清楚  例如: {@link BigInteger#probablePrime(int, Random)}
     *
     *      2. invoke 时，可以不创建新对象，而返回已经创建过的对象
     *              例如: {@link Boolean#valueOf(boolean)} 不会新建一个对象返回
     *
     *      3. 可以返回任意子类
     *
     *      4. 可以根据参数值的不同，返回不同的对象
     *              例如: {@link EnumSet#noneOf(Class)} 方法，根据元素值是否大于64返回不同的子类
     *
     *      5. 在编写静态工厂方法时，返回的类 可以不存在
     *              例如 jdbc 接口
     *  例子:
     *      from    Date.from(instant)  {@link java.util.Date#from(Instant)}
     *      of      EnumSet.of(., ., .) {@link java.util.EnumSet#of(Enum, Enum[])})}
     *      valueOf
     *      instance or getInstance
     *      create or newInstance
     *      getType
     *      newType
     *      type
     *
     *  缺点：
     *      1. 与其他静态方法无明显区别，难以极快速找到
     *      2. 没有 public/protected 构造器的类，不能被继承，产生子类
     */
    public static void useStaticFactoryMethods() {
    }

    /** Item 2
     * 构造器参数过多时，使用 Builder 模式
     *      例子:
     */
    public static void useBuilderWhenManyArgs() {

    }

    /*
     * Item3 单例
     * java1.5之前，实现 单例模式的两种方法：
     * 1. private 构造器 + public static final 公有对象
     * 2. private 构造器 + private static final 私有对象 + public static(静态工厂方法)
     * 问题：
     *      使用反射调用 构造器或工厂方法，可能会创建不同的对象，需要抛出异常
     *      反序列化创建，可能会创建新对象，需要添加 readResolve()方法返回 (实际上反射调用了readResolve()方法)
     *      多线程调用 可能会造成创建多个对象
     * java1.5之后，第3种方法
     * 3. 单元素枚举（Enum）类   实现
     */
    public void singletonWithEnum() {
    }

    /**
     * Item4
     * 不想被实例化的类
     *      如果要设计一个类，只有static方法，static属性，要防止其被实例化，被继承该如何做？
     *      使用 private 构造器，在构造器中 throw new AssertionError()
     *
     */
    public void notToBeInstantiated() {

    }


    /**
     * Item 5
     * 依赖注入的实现 Dependency injection
     * 依赖注入的不好的实现：static类 或 单例模式    原因：不灵活，无法改变依赖的对象
     * <p>
     * 推荐实现：使用一个传入参数是依赖对象的构造器，或者一个 传入参数是工厂对象的构造器
     * <p>
     * 但是有些对象的依赖项过多，解决办法是使用框架：Spring, Guice, Dagger
     */
    public void dependencyInjection() {
    }

    /**
     * Item6
     * 避免创建不必要的对象
     *      1. 重用不可变的对象
     *      2. 实例化后就不更改的可变对象，可以放在static代码块中 或放在对象池中（池化适用于创建对象代价昂贵的情形）
     *              例： "regex".matches()  改为 static final Pattern， 例2：  数据库连接池
     *      3. 能用基本类型不要用装箱类型（装箱类型会创建对象）
     */

    /**
     * Item7
     * 避免内存泄漏 - 消除过期的对象引用

     * Item8
     * 避免使用终结方法 finalizers 或 cleaner（java9）
     *
     * Item9
     * 使用 try with resources 而不是 try finally
     */
}
